home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
pcpilot.exe
/
lha
/
TSR.C
< prev
next >
Wrap
Text File
|
1990-01-13
|
11KB
|
402 lines
/*
TSR.C
Original code from Al Stevens' book "Extending Turbo C Professional"
slightly modified by Tom Grubbe
NOTE: In the listing in his book, Mr. Stevens #includes "interrupt.h"
which is nowhere to be found in the entire book! However with
some added #defines and the IREGS structure this module compiles
and performs without errors.
*/
#include <stdio.h>
#include <dos.h>
#include <stdlib.h>
#include <conio.h>
#define TRUE 1
#define FALSE 0
/* --- vectors ---- */
#define DISK 0x13
#define INT28 0x28
#define KYBRD 0x9
#define CRIT 0x24
#define DOS 0x21
#define CTRLC 0x23
#define CTRLBRK 0x1b
#define TIMER 0x1c
typedef struct {
int bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,fl;
} IREGS;
unsigned scancode;
unsigned keymask;
extern char signature[];
int unloading; /* TSR unload flag */
static void (*UserRtn)(void); /* Pointer to user's start routine */
static void (*InitRtn)(void); /* Pointer to user's initialization routine */
/* ---- interrupt vector chains ----- */
static void interrupt (*oldbreak)(void);
static void interrupt (*oldctrlc)(void);
static void interrupt (*oldtimer)(void);
static void interrupt (*old28)(void);
static void interrupt (*oldkb)(void);
static void interrupt (*olddisk)(void);
static void interrupt (*oldcrit)(void);
/* ------ ISRs fot the TSR --------- */
static void interrupt newtimer(void);
static void interrupt new28(void);
static void interrupt newkb(void);
static void interrupt newdisk(IREGS);
static void interrupt newcrit(IREGS);
static void interrupt newbreak(void);
static unsigned sizeprogram;/* TSR's program size */
static unsigned dosseg; /* DOS segment address */
static unsigned dosbusy; /* offset to InDos flag */
static unsigned psps[2]; /* table of DOS PSP addresses */
static int pspctr; /* # of DOS PSP addresses */
static int diskflag; /* disk BIOS busy flag */
static unsigned mcbseg; /* address of 1st DOS mcb */
static char far *mydta; /* TSR's DTA */
static unsigned myss; /* TSR's stack segment */
static unsigned mysp; /* TSR's stack pointer */
static unsigned intpsp; /* Interrupted PSP address */
static int running; /* TSR running indicator */
static int hotkey_flag; /* Hotkey pressed flag */
/* ------ local prototypes ------- */
void tsr(void (*FPtr)(void), void (*InitFPtr)(void));
static void tsr_init(void);
static void resinit(void);
static void unload(void);
static void resterm(void);
static void pspaddr(void);
static void dores(void);
static void resident_psp(void);
static void interrupted_psp(void);
static int resident(char *signature);
static int test_hotkeys(int ky);
#define signon(s) printf("\n%s %s", signature, s);
void tsr(void (*FPtr)(void), void (*InitFPtr)(void))
{
UserRtn = FPtr;
InitRtn = InitFPtr;
tsr_init();
if (resident(signature) == FALSE) {
/* ------- initial load of TSR program -------- */
#ifdef DEBUG
(*UserRtn)();
return;
#else
/* ------- Terminate and Stay Resident -------- */
(*InitRtn)(); /* user's init function */
resinit();
#endif
}
signon("is already installed.\n");
}
/* --------- initialize TSR control values ---------- */
static void tsr_init()
{
unsigned es, bx;
/* --------- get address of DOS busy flag --------- */
_AH = 0x34;
geninterrupt(DOS);
dosseg = _ES;
dosbusy = _BX;
/* --------- get the seg addr of 1st DOS MCB --------- */
_AH = 0x52;
geninterrupt(DOS);
es = _ES;
bx = _BX;
mcbseg = peek(es, bx-2);
/* --------- get address of resident program's dta -------- */
mydta = getdta();
/* --------- get address of PSP in DOS 2.x --------- */
if (_osmajor < 3)
pspaddr();
}
/* --------- establish & declare residency ---------- */
static void resinit()
{
myss = _SS;
mysp = _SP;
oldtimer = getvect(TIMER);
old28 = getvect(INT28);
oldkb = getvect(KYBRD);
olddisk = getvect(DISK);
/* ------- attach vectors to resident program ------- */
setvect(TIMER, newtimer);
setvect(KYBRD, newkb);
setvect(INT28, new28);
setvect(DISK, newdisk);
/* -------- compute program's size -------- */
sizeprogram = myss + ((mysp+50) / 16) - _psp;
/* -------- terminate and stay resident -------- */
keep(0, sizeprogram);
}
/* --------- break handler ----------- */
static void interrupt newbreak()
{
return;
}
/* ---------- critical error ISR --------- */
static void interrupt newcrit(IREGS ir)
{
ir.ax = 0; /* ignore critical errors */
}
/* -------- BIOS disk functions ISR --------- */
static void interrupt newdisk(IREGS ir)
{
diskflag++;
(*olddisk)();
ir.ax = _AX; /* for the register returns */
ir.cx = _CX;
ir.dx = _DX;
ir.fl = _FLAGS;
--diskflag;
}
/* -------- test for the hotkey --------- */
static int test_hotkeys(int ky)
{
static unsigned biosshift;
biosshift = peekb(0, 0x417);
if (ky == scancode && (biosshift & keymask) == keymask)
hotkey_flag = !running;
return hotkey_flag;
}
/* --------- keyboard ISR ---------- */
static void interrupt newkb()
{
static int kbval;
if (test_hotkeys(inportb(0x60))) {
/* reset the keyboard */
kbval = inportb(0x61);
outportb(0x61, kbval | 0x80);
outportb(0x61, kbval);
outportb(0x20, 0x20);
}
else
(*oldkb)();
}
/* --------- timer ISR ---------- */
static void interrupt newtimer()
{
(*oldtimer)();
test_hotkeys(0);
if (hotkey_flag && peekb(dosseg, dosbusy) == 0) {
if (diskflag == 0) {
outportb(0x20, 0x20);
hotkey_flag = FALSE;
dores();
}
}
}
/* ---------- 0x28 ISR ---------- */
static void interrupt new28()
{
(*old28)();
if (hotkey_flag && peekb(dosseg, dosbusy) != 0) {
hotkey_flag = FALSE;
dores();
}
}
/* ------ switch psp context from interrupted to TSR ------ */
static void resident_psp()
{
int pp;
if (_osmajor < 3) {
/* --- save interrupted program's psp (DOS 2.x) ---- */
intpsp = peek(dosseg, *psps);
/* ------- set resident program's psp ------- */
for (pp = 0; pp < pspctr; pp++)
poke(dosseg, psps[pp], _psp);
}
else {
/* ----- save interrupted program's psp ------ */
intpsp = getpsp();
/* ------ set resident program's psp ------- */
_AH = 0x50;
_BX = _psp;
geninterrupt(DOS);
}
}
/* -------- switch psp context from TSR to interrupted --------- */
static void interrupted_psp()
{
int pp;
if (_osmajor < 3) {
/* --- reset interrupted psp (DOS 2.x) ---- */
for (pp = 0; pp < pspctr; pp++)
poke(dosseg, psps[pp], intpsp);
}
else {
/* ------ reset interrupted psp ------- */
_AH = 0x50;
_BX = intpsp;
geninterrupt(DOS);
}
}
/* -------- execute the resident program ---------- */
static void dores()
{
static char far *intdta; /* interrupted DTA */
static unsigned intsp; /* " stack pointer */
static unsigned intss; /* " stack segment */
static unsigned ctrl_break; /* Ctrl-Break setting */
running = TRUE; /* set TSR running metaphore */
disable();
intsp = _SP;
intss = _SS;
_SP = mysp;
_SS = myss;
oldcrit = getvect(CRIT);
oldbreak = getvect(CTRLBRK);
oldctrlc = getvect(CTRLC);
setvect(CRIT, newcrit);
setvect(CTRLBRK, newbreak);
setvect(CTRLC, newbreak);
ctrl_break = getcbrk(); /* get ctrl break setting */
setcbrk(0); /* turn off ctrl break logic */
intdta = getdta(); /* get interrupted dta */
setdta(mydta); /* set resident dta */
resident_psp(); /* swap psps */
enable();
(*UserRtn)(); /* call the TSR program here */
disable();
interrupted_psp(); /* reset interrupted psp */
setdta(intdta); /* reset